package com.douqu.game.core.entity.battle;


import com.douqu.game.core.controller.BattleParentController;
import com.douqu.game.core.controller.SpriteController;
import com.douqu.game.core.e.E_SkillType;
import com.douqu.game.core.entity.EntityObject;
import com.douqu.game.core.entity.Skill;
import com.douqu.game.core.factory.ConstantFactory;
import com.douqu.game.core.util.Utils;
import org.apache.log4j.Logger;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created by bean on 2017/8/10.
 */
public class BattleSkill extends EntityObject {

    Logger logger = Logger.getLogger(BattleSkill.class);

    private SpriteController spriteController;

    private BattleAObject battleAObject;

    public Skill skill;

    /**
     * 释放时间
     */
    public long releaseTime;

    public int releaseCount;

    /**
     * 当前剩余CD时间
     */
    public int cdTime;

    /**
     * 技能生效的位置
     */
    private Position effectPos;

    /**
     * 技能锁敌
     */
    private List<BattleAObject> effectTargets;

    /**
     * 剩余效果时间,若为0则表示要生效了
     */
    private int effectTime;

    public BattleSkill(SpriteController spriteController, BattleAObject battleAObject, Skill skill)
    {
        this.spriteController = spriteController;
        this.battleAObject = battleAObject;
        this.skill = skill;
    }


    public void update(int updateTime)
    {
        if(cdTime > 0)
        {
            cdTime -= updateTime;
            cdTime = cdTime < 0 ? 0 : cdTime;
        }

        if(effectTime > 0)
        {
            effectTime -= updateTime;
            effectTime = effectTime < 0 ? 0 : effectTime;
        }
    }

    public boolean isHaveTarget()
    {
        return effectTargets != null && effectTargets.size() > 0;
    }

    public void checkTargetDie()
    {
        if(effectTargets == null)
            return;

        for(BattleAObject target : effectTargets)
        {
            if(target.isDie())
            {
                effectTargets.remove(target);
            }
        }
    }

    public void addAtkTarget(BattleAObject target)
    {
        if(effectTargets == null)
            effectTargets = new CopyOnWriteArrayList<>();

        effectTargets.add(target);
    }

    public void addAtkTarget(List<BattleAObject> targets)
    {
        effectTargets = targets;
    }

    public void clearAtkTarget()
    {
        if(effectTargets != null)
        {
            effectTargets.clear();
        }
    }

    public BattleAObject getFirstTarget()
    {
        if(isHaveTarget())
            return effectTargets.get(0);

        return null;
    }

    public List<BattleAObject> getTargets()
    {
        return effectTargets;
    }

    public void initCDTime()
    {
        cdTime = skill.cdTime;
    }

    /**
     * 是否能进行目标检测
     * 用来判断普通技能
     * @return
     */
    public boolean isCheckTarget()
    {
        return effectTime == 0;
    }

    /**
     * 是否是延时效果
     * @return
     */
    public boolean isTimeAction()
    {
        return skill.actionTime > 0;
    }

    /**
     * 是否在播放动作中
     * @return
     */
    public boolean isTimeActioning()
    {
        return skill.actionTime > 0 && effectTime > 0;
    }


    /**
     * 是否能释放了
     * @param currentTime
     * @return
     */
    public boolean isCanRelease(long currentTime)
    {
        return releaseTime == 0 || currentTime - releaseTime >= skill.cdTime;
    }

    public boolean isCanReleaseMasterSkill()
    {
        return cdTime == 0;
    }


    public void setReleaseInfo(long time)
    {
        releaseTime = time;
        releaseCount++;
    }



    public void release(Position targetPosition, long currentTime, BattleAObject target)
    {
        List<BattleAObject> targets = new CopyOnWriteArrayList<>();
        targets.add(target);
        release(targets, targetPosition, currentTime);
    }

    /**
     * 释放技能
     * @param targets
     * @param targetPosition
     */
    public void release(List<BattleAObject> targets, Position targetPosition, long currentTime)
    {
        if((targets == null || targets.size() == 0) && targetPosition == null)
            return;

        logger.info("BattleSkill release 释放技能 -> 攻击者:" + battleAObject + " 技能:" + skill.id + "-" + skill.name + " 被攻击者:" + targets);
        if(skill.actionTime == 0)//及时
        {
            if((targets == null || targets.size() == 0) && targetPosition != null)
            {
                targets = battleAObject.battleParentController.getSkillTargets(this, targetPosition);
            }

            if(targets.size() > 0)
            {
                releaseFlash(targets, targetPosition);
            }
        }
        else
        {
            //延时效果,先计算生效时间
            if(skill.isLockTarget())
            {
                //锁敌
                if(targets != null && targets.size() > 0)
                {
                    double distance = Utils.getDistance(battleAObject.getPosition(), targets.get(0).getPosition());
                    logger.info("BattleSkill release time1:" + skill.actionTime + " distance:" + distance);
                    releaseTime(battleAObject.battleParentController.getSkillTargets(this, targets, true), skill.actionTime);
                }
                else if(targetPosition != null)
                {
                    double distance = Utils.getDistance(battleAObject.getPosition(), targetPosition);
                    logger.info("BattleSkill release time2:" + skill.actionTime + " distance:" + distance);
                    releaseTime(battleAObject.battleParentController.getSkillTargets(this, targetPosition), skill.actionTime);
                }
            }
            else
            {
                Position targetPos = null;
                if(targets != null && targets.size() > 0)
                {
                    targetPos = targets.get(0).getPosition();
                }
                else if(targetPosition != null)
                {
                    targetPos = targetPosition;
                }
                if(targetPos != null)
                {
                    double distance = Utils.getDistance(battleAObject.getPosition(), targetPos);
                    logger.info("BattleSkill release time2:" + skill.actionTime + " distance:" + distance);
                    releaseTime(targetPos, skill.actionTime);
                }
            }
        }

        setReleaseInfo(currentTime);
    }

    /**
     * 针对单个目标释放技能
     * @param target
     */
    public void damage(BattleAObject target)
    {
        if(target == null)
            return;

        E_SkillType hpType = skill.getType();
        if(hpType == E_SkillType.HP_SUB)
        {
            int damage = battleAObject.getDamage(target, skill);
            target.addHP(-damage);

            logger.info("技能释放者:" + battleAObject.getName() + " 伤害目标:" + target.getName() + " BattleSkill release 剩余血量:" + target.getHp() + " 技能:" + skill.getName());

            battleAObject.battleParentController.sendDamage(target.id, -damage, target.getHp());
        }
        else if(hpType == E_SkillType.HP_ADD)
        {
            int addHP = battleAObject.getAddHP(skill);
            target.addHP(addHP);

            logger.info("技能释放者:" + battleAObject.getName() + " 加血目标:" + target.getName() + " BattleSkill release 剩余血量:" + target.getHp() + " 技能:" + skill.getName());

            battleAObject.battleParentController.sendDamage(target.id, addHP, target.getHp());
        }
        else if(hpType == E_SkillType.ATT_ADD)
        {

        }
        else if(hpType == E_SkillType.ATT_SUB)
        {

        }
    }


    /**
     * 及时效果释放
     * @param targets
     */
    public void releaseFlash(List<BattleAObject> targets, Position position)
    {
        logger.info("BattleSkill releaseFlash 释放及时效果!");
        battleAObject.battleParentController.sendUseSkill(skill.getId(), battleAObject.getId(), targets, 0, position);

        for(BattleAObject target : targets)
        {
            damage(target);
        }
    }


    /**
     * 延时效果释放
     */
    public void releaseTime(Position position, double time)
    {
        logger.info("BattleSkill releaseFlash 释放延时效果 -> 针对指定位置:" + position + " 技能:" + skill.getName());

        battleAObject.battleParentController.sendUseSkill(skill.getId(), battleAObject.getId(), null, (int) time, position);

        effectTargets = null;
        effectPos = position;
        effectTime = (int) time;
    }

    /**
     * 延时效果释放
     */
    public void releaseTime(List<BattleAObject> targets, double time)
    {
        logger.info("BattleSkill releaseFlash 释放延时效果 -> 针对指定目标:" + targets + " 技能:" + skill.getName());

        if(targets == null || targets.size() == 0)
            return;

        battleAObject.battleParentController.sendUseSkill(skill.getId(), battleAObject.getId(), targets, (int) time, null);

        effectPos = null;
        addAtkTarget(targets);
        effectTime = (int) time;
    }

    /**
     * 延时效果生效
     */
    public void timeEffectStart(BattleParentController battleController)
    {
        logger.info("BattleSkill timeEffectStart 延时效果时间到了，触发伤害 -> effectPos:" + effectPos + " targets:" + effectTargets + " 技能:" + skill.getName());
        if(effectPos != null)
        {
            if(effectTime <= 0)
            {
                List<BattleAObject> targets = battleController.getSkillTargets(this, effectPos);
                if(targets != null)
                {
                    for(BattleAObject target: targets)
                    {
                        damage(target);
                    }
                }

                effectPos = null;
            }
        }
        else if(effectTargets != null)
        {
            for(BattleAObject target: effectTargets)
            {
                damage(target);

                if(target.isDie())
                {
                    effectTargets.remove(target);
                }
            }

            effectTargets = null;
        }
    }

    /**
     * 延时效果是否能生效
     * @return
     */
    public boolean checkTimeEffectStart()
    {
        return (effectPos != null || effectTargets != null) && effectTime <= 0 && skill.actionTime > 0;
    }


    /**
     * 检测技能是否能对此单位有效果
     * @param target
     * @return
     */
    public boolean checkUnitType(BattleAObject target)
    {
        return skill.checkUnitType(target);
    }

    public boolean checkTargetType(BattleAObject source, BattleAObject target)
    {
        return skill.checkTargetType(source ,target);
    }

    /**
     * 是否在攻击范围内
     * @param source
     * @param target
     * @return
     */
    public boolean isInAtkRange(BattleAObject source, BattleAObject target)
    {
        return skill.isInAtkRange(source, target);
    }

    public boolean isInAtkRange(Position source, int teamNo, BattleAObject target)
    {
        return skill.isInAtkRange(source, teamNo, target);
    }

    public boolean isSingleTarget()
    {
        return skill.isSingleTarget();
    }
    /**
     * 获取攻击点
     * @return
     */
    public Position getAtkPosition()
    {
        if(skill.effectRange[0] == ConstantFactory.RANGE_TYPE_CIRCLE)
        {

        }
        else if(skill.effectRange[0] == ConstantFactory.RANGE_TYPE_RECTANGLE)
        {

        }

        return battleAObject.position;
    }



    /**
     * 是否是锁敌技能
     * @return
     */
    public boolean isLockTarget()
    {
        return skill.isLockTarget();
    }

    public int getId()
    {
        return skill.id;
    }

    public Skill getSkill()
    {
        return skill;
    }

    public BattleAObject getReleaser()
    {
        return battleAObject;
    }

    public SpriteController getMasterController()
    {
        return spriteController;
    }


}
